import aiohttp
import logging
import json
import time
from typing import Dict, Any, Optional, Union

logger = logging.getLogger(__name__)

class HttpClient:
    """
    异步HTTP客户端
    处理HTTP请求的发送和接收
    """
    
    def __init__(self, base_url: str = "", timeout: int = 30):
        """
        初始化HTTP客户端
        
        参数:
            base_url: API基础URL
            timeout: 请求超时时间（秒）
        """
        self.base_url = base_url
        self.timeout = timeout
        self.session = None
    
    async def ensure_session(self):
        """确保aiohttp会话已创建"""
        if self.session is None or self.session.closed:
            self.session = aiohttp.ClientSession()
    
    async def close(self):
        """关闭会话"""
        if self.session and not self.session.closed:
            await self.session.close()
            self.session = None
    
    async def request(
        self, 
        method: str, 
        url: str, 
        params: Optional[Dict[str, Any]] = None, 
        data: Optional[Union[Dict[str, Any], str]] = None,
        headers: Optional[Dict[str, str]] = None,
        timeout: Optional[int] = None,
        base_url: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        发送HTTP请求
        
        参数:
            method: 请求方法（GET, POST, PUT, DELETE等）
            url: 请求URL
            params: URL参数
            data: 请求体数据
            headers: 请求头
            timeout: 请求超时时间（秒）
            base_url: 覆盖默认的base_url
            
        返回:
            响应数据（JSON解析后的字典）
            
        异常:
            HttpError: 请求失败时抛出
        """
        await self.ensure_session()
        
        full_url = f"{base_url or self.base_url}{url}"
        timeout_value = timeout or self.timeout
        headers = headers or {}
        
        start_time = time.time()
        try:
            logger.debug(f"发送请求: {method} {full_url}")
            logger.debug(f"参数: {params}")
            logger.debug(f"数据: {data}")
            
            async with self.session.request(
                method=method,
                url=full_url,
                params=params,
                data=data,
                headers=headers,
                timeout=aiohttp.ClientTimeout(total=timeout_value)
            ) as response:
                response_text = await response.text()
                elapsed = time.time() - start_time
                
                logger.info(f"收到响应: {response.status} ({elapsed:.3f}s)")
                logger.info(f"响应内容: {response_text[:1000]}...")
                
                if response.status >= 400:
                    raise HttpError(
                        status_code=response.status,
                        message=f"HTTP请求失败: {response.status}",
                        response_text=response_text
                    )
                
                try:
                    return json.loads(response_text)
                except json.JSONDecodeError:
                    raise HttpError(
                        status_code=response.status,
                        message="无效的JSON响应",
                        response_text=response_text
                    )
                    
        except aiohttp.ClientError as e:
            elapsed = time.time() - start_time
            logger.error(f"请求异常: {e} ({elapsed:.3f}s)")
            raise HttpError(
                status_code=None,
                message=f"请求异常: {str(e)}",
                original_error=e
            )

class HttpError(Exception):
    """HTTP请求错误"""
    
    def __init__(
        self, 
        message: str, 
        status_code: Optional[int] = None,
        response_text: Optional[str] = None,
        original_error: Optional[Exception] = None
    ):
        self.message = message
        self.status_code = status_code
        self.response_text = response_text
        self.original_error = original_error
        super().__init__(message) 